# algorithm/models/user_comprehensive_level.py
from django.db import models
from django.contrib.auth.models import User
from ..utils import mastery_level1, level_threshold_count
from users.models import User as CustomUser  # 自定义的User表
from tag.models import AlgorithmTag  # 使用 AlgorithmTag 代替 Tag
from problems.models import Problem
from .tag_values import TagValue
from .user_tag_mastery import UserTagMastery
from recommendation.models import SolvedProblem
from django.core.exceptions import ObjectDoesNotExist
import logging
logger = logging.getLogger('algorithm')


# 用户综合水平模型
class UserComprehensiveLevel(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    # 标签综合掌握度
    tag_solving_level = models.FloatField(default=0.0)
    # 用户综合水平
    user_level = models.FloatField(default=0.0)

    def __str__(self):
        return f"{self.user.username} - tag_solving_level: {self.tag_solving_level}, user_level: {self.user_level}"

    # 备忘录模式
    def save_state(self):
        return {
            'tag_solving_level': self.tag_solving_level,
            'user_level': self.user_level
        }

    @staticmethod
    def restore_state(user, state_data):
        obj, created = UserComprehensiveLevel.objects.update_or_create(
            user=user,
            defaults=state_data
        )
    # 这个设计比较不错，为数据模型里的所有字段在一个方法里提供create_or_update

    @classmethod
    def create_or_update_user_level(cls, user_id):
        try:
            # 尝试获取用户实例
            user = User.objects.get(id=user_id)

            # 计算标签综合掌握度，确保方法返回有效数据或处理异常
            tag_solving_level = cls.calculate_tag_solving_level(user_id)
            if tag_solving_level is None:
                tag_solving_level = 0.0  # 如果无法计算，则默认为0

            # 计算用户综合水平，确保方法返回有效数据或处理异常
            user_level = cls.calculate_user_level(user_id)
            if user_level is None:
                user_level = 0.0  # 如果无法计算，则默认为0

            # 更新或创建用户综合水平记录
            user_comprehensive_level, created = cls.objects.update_or_create(
                user=user,
                defaults={
                    'tag_solving_level': tag_solving_level,
                    'user_level': user_level
                }
            )
            logger.info(f"{cls.__name__}.create_or_update_user_level({user_id} user:{user.username}) Success : tag_solving_level = {tag_solving_level}, user_level = {user_level}" )
            return user_comprehensive_level, created
        except ObjectDoesNotExist:
            print(f"User with ID {user_id} does not exist.")
            logger.error(f"{cls.__name__}.create_or_update_user_level : User {user_id} does not exist.")
            return None, False
        except Exception as e:
            print(f"An error occurred while creating or updating user level: {str(e)}")
            logger.error(f"{cls.__name__}.create_or_update_user_level : Error {str(e)}")
            return None, False

    @classmethod
    def calculate_tag_solving_level(cls, user_id):
        try:
            # 获取用户实例
            user = User.objects.get(id=user_id)

            # 计算所有TagValue的总和
            total_tag_value = TagValue.objects.aggregate(sum=models.Sum('tag_value'))['sum']
            if total_tag_value == 0:
                # 如果总和为0，避免除零错误
                print("Total tag value is zero, avoiding division by zero.")
                return None

            # 计算标签综合掌握度
            tag_solving_level = 0.0
            tags = AlgorithmTag.objects.all()
            for tag in tags:
                tag_value = TagValue.objects.get(tag=tag).tag_value
                mastery_entry = UserTagMastery.objects.get(user=user, tag=tag)
                tag_solving_level += (tag_value * mastery_entry.mastery_level) / total_tag_value

            return tag_solving_level
        except User.DoesNotExist:
            print(f"No user found with ID {user_id}")
        except TagValue.DoesNotExist:
            print("TagValue not found for some tags.")
        except UserTagMastery.DoesNotExist:
            print("UserTagMastery entry missing for some user-tag combinations.")
        except Exception as e:
            print(f"An error occurred: {str(e)}")

    @classmethod
    def calculate_user_level(cls, user_id):
        try:
            user = User.objects.get(id=user_id)

            # 初始化每个难度级别的计数数组
            difficulty_counts = [0] * 8

            # 获取用户已解决的题目
            solved_problems = SolvedProblem.objects.filter(user=user).select_related('problem')

            # 计算用户解决的各难度题目数
            for sp in solved_problems:
                if 0 <= sp.problem.difficulty_index <= 7:
                    difficulty_counts[sp.problem.difficulty_index] += 1

            # 定义衰减因子
            decay_factors = [0] + [0.5 ** (7 - i) for i in range(1, 8)]

            # 使用衰减因子计算适合难度
            weighted_sum = sum(i * difficulty_counts[i] * decay_factors[i] for i in range(1, 8))
            total_weight = sum(difficulty_counts[i] * decay_factors[i] for i in range(1, 8))

            # 计算用户适合的难度级别，如果没有完成任何有效难度的题目，返回最低难度
            suitable_difficulty = weighted_sum / total_weight if total_weight > 0 else 1.0

            return suitable_difficulty
        except User.DoesNotExist:
            print(f"No user found with ID {user_id}")
            return None
        except Exception as e:
            print(f"An error occurred: {str(e)}")
            return None

    @classmethod
    def print_user_comprehensive_level_info(cls, user_id):
        try:
            user = User.objects.get(id=user_id)
            usercomprehensivelevel = UserComprehensiveLevel.objects.get(user=user)
            print("username:")
            print(usercomprehensivelevel.user.username)
            print("tag_solving_level:")
            print(usercomprehensivelevel.tag_solving_level)
            print("user_level:")
            print(usercomprehensivelevel.user_level)
        except User.DoesNotExist:
            print(f"No user found with ID {user_id}")
        except Exception as e:
            print(f"An error occurred: {str(e)}")

    @classmethod
    def update_user_comprehensive_level(cls, user_id):
        try:
            cls.create_or_update_user_level(user_id)
            print(f"Successfully User Comprehensive Level for user_id={user_id}")
        except Exception as e:
            print(f"An error occurred while updating User Comprehensive Level user_id={user_id}: {e}")

